package cn.bluedot.framework.core;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 类扫描器
 */
public class ClassScanner {

    /**
     * 	扫描包
     * @param packageName  包名
     * @return
     * @throws IOException
     */
    public static List<Class<?>> scanClasses(String packageName) throws IOException, ClassNotFoundException {
    	
    	List<Class<?>> classList = new ArrayList<Class<?>>();  //存储扫描到的类
        
    	String path = packageName.replace(".", "/");  //包名转换为文件路径
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); //获取默认类加载器
        Enumeration<URL> resources = classLoader.getResources(path); //获取URL资源
        
        while(resources.hasMoreElements()){
        	
            URL resource = resources.nextElement();  //获取资源

            if(resource.getProtocol().contains("jar")){ //获取资源类型
                JarURLConnection jarURLConnection = (JarURLConnection) resource.openConnection();
                String jarFilePath = jarURLConnection.getJarFile().getName(); //获取资源jar包路径
                classList.addAll(getClassesFromJar(jarFilePath,path));
            } else if(resource.getProtocol().contains("file")){
            	String filePath = resource.getFile();  //获取文件的绝对路径
            	classList = getClassesFromFile(filePath,path,classList);
            }
        }
        
        if(classList.isEmpty()) {
        	throw new IOException("Initialization from '"+packageName+"' for class  failed; the package were inexistence");
        }
        
        return classList;
    }

    /**
     *  通过文件路径获取所有类
     * @param filePath 绝对路径
     * @param path 包基础路径
     * @param classes  装载Class的容器
     * @return 指定包下的所有类
     * @throws ClassNotFoundException
     */
    private static List<Class<?>> getClassesFromFile(String filePath, String path,List<Class<?>> classes) throws ClassNotFoundException {
    	  	
    	final File file = new File(filePath);
		    	
    	File[] files = file.listFiles(new FileFilter() {
			
			@Override
			public boolean accept(File pathname) {
				if(file.isDirectory()) { //自定义过滤规则，获取目录或者.class文件
					return true;
				}
				return pathname.getName().endsWith(".class");
			}
		});
		
		for (File child : files) {
						
			if(child.isDirectory()) { //深入目录递归扫描
				getClassesFromFile(child.getAbsolutePath(), path+"/"+child.getName(),classes);
			} else {
				String entryName = path+"/"+child.getName(); //com/laoxuai/mvc/Controller.class
				
				String classFullName = entryName.replace("/", ".").substring(0, entryName.length() - 6); //获取全限类名com.laoxuai.mvc.Controller
				classes.add(Class.forName(classFullName));
			}
			
		}
		return classes;
	}


	/**
     * 	通过jar包路径获取所有类
     * @param jarFilePath  jar包路径
     * @param path  相对路径
     * @return
     */
    private static List<Class<?>> getClassesFromJar(String jarFilePath, String path) throws IOException, ClassNotFoundException {

        List<Class<?>> classes = new ArrayList<Class<?>>();
        JarFile jarFile = new JarFile(jarFilePath);  //根据jarFile实例

        Enumeration<JarEntry> jarEntries = jarFile.entries();

        while(jarEntries.hasMoreElements()){
            JarEntry jarEntry = jarEntries.nextElement();
            String entryName = jarEntry.getName(); //  com/laoxuai/mvc/Controller.class

            if(entryName.startsWith(path) && entryName.endsWith(".class")){
                String classFullName = entryName.replace("/", ".").substring(0, entryName.length() - 6); //获取全限类名

                classes.add(Class.forName(classFullName)); //类加载实例
            }
        }
        jarFile.close();

        return classes;
    }

}
